package com.liu.netty.demo.client;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

/**
 * @program: https://www.joinsunsoft.com
 * @description:
 * @author: LiuYong
 * @email: david.liu@ginghan.com
 * @create: 2022/3/22 21:02
 */

@Slf4j
public abstract class DemoServer {

    @Getter
    @Setter
    private Integer port;

    @Getter
    @Setter
    private String name;

    /**
     * boss 线程组用于处理连接工作
     */
    @Getter
    private EventLoopGroup boss = new NioEventLoopGroup();
    /**
     * work 线程组用于数据处理
     */
    @Getter
    private EventLoopGroup work = new NioEventLoopGroup();

    protected abstract ChannelHandler[] initHandler();

    public void start(){
        start(false);
    }

    public void start(boolean blocked){

        ServerBootstrap bootstrap = new ServerBootstrap();

        ChannelFuture future = null;

        bootstrap.group(boss,work);

        try{

            bootstrap.channel(NioServerSocketChannel.class);

            bootstrap.childHandler(new ChannelInitializer<Channel>() {
                @Override
                protected void initChannel(Channel channel) throws Exception {

                    channel.pipeline().addLast(new IdleStateHandler(300,300,600, TimeUnit.SECONDS));
//                    channel.pipeline().addLast(new LengthFieldBasedFrameDecoder(ByteOrder.BIG_ENDIAN,
//                            655360,0,2,0,2,true));

                    channel.pipeline().addLast(new HeartBeatServerHandler());

                    channel.pipeline().addLast(initHandler());
                }
            });

            bootstrap.option(ChannelOption.SO_BACKLOG, 2048);//serverSocketchannel的设置，链接缓冲池的大小
            bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);//socketchannel的设置,维持链接的活跃，清除死链接
            bootstrap.childOption(ChannelOption.TCP_NODELAY, true);//socketchannel的设置,关闭延迟发送

            future = bootstrap.bind(port).sync();

            if(future.isSuccess()){
                log.info("Server {}[:{}] is  started !!!", name, port);
            }
            else{
                log.info("Server {}[:{}] is  started fail!!!", name, port);
            }

            if(blocked)
                future.channel().closeFuture().sync();

        }catch (Throwable t)
        {
            log.error("{}[:{}] error", name, port);
            log.error("error:", t);
        }
        finally {
            if(blocked)
                destory();
        }
    }

    public void destory(){
        try{

            if(boss!=null)
                boss.shutdownGracefully().sync();
        }catch (Exception e){
            log.error("Shutdown boss Event error", e);
        }

        try{

            if(work!=null)
                work.shutdownGracefully().sync();
        }catch (Exception e){
            log.error("Shutdown boss Event error", e);
        }

        log.info("关闭{}[:{}]", name, port);
    }

}
